#include "ds1307.h"
#include "public.h"
#include "iic.h"

u8 gDS1302_TIME[7]={0x00,0x41,0x20,0x06,0x25,0x01,0x25};
/*******************************************************************************
  * 函数名：DS1307_WriteReg
  * 功  能：写寄存器
  * 参  数：addr：寄存器地址
            data：写入的数据
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void DS1307_WriteReg(u8 addr, u8 dat)
{
	iic_start();//起始信号
	IIC_WriteByte(DEV_ADDR | WRITE_CMD);//器件寻址+写
	IIC_WaitAck();//等待应答
	IIC_WriteByte(addr);//地址
	IIC_WaitAck();//等待应答
	IIC_WriteByte(dat);
	IIC_WaitAck();//等待应答
	IIC_Stop();
}
/*******************************************************************************
  * 函数名：DS1307_ReadReg
  * 功  能：读寄存器
  * 参  数：addr：寄存器地址
  * 返回值：data：读出的数据
  * 说  明：无
***************  ****************************************************************/
u8 DS1307_ReadReg(u8 addr)
{
	u8 dat = 0;
	iic_start();//起始信号	
	IIC_WriteByte(DEV_ADDR | WRITE_CMD);//器件寻址+写
	IIC_WaitAck();//等待应答
	IIC_WriteByte(addr);//地址
	IIC_WaitAck();//等待应答
	iic_start();//起始信号
	IIC_WriteByte(DEV_ADDR | READ_CMD);//器件寻址+读
	IIC_WaitAck();//等待应答
	dat = IIC_ReadByte(READ_CMD);
	IIC_NoAck();
	IIC_Stop();
	return dat;
}

/*******************************************************************************
  * 函数名：DS1307_GetYear
  * 功  能：获取年份
  * 参  数：无			
  * 返回值：年份，十进制
  * 说  明：将BCD码转为十进制
*******************************************************************************/
u16 DS1307_GetYear(void)
{
	u16 temp = 0;
	temp = DS1307_ReadReg(REG_YEAR);
	return BCDToDec(temp);
}
/*******************************************************************************
  * 函数名：DS1307_GetDay
  * 功  能：获取星期几
  * 参  数：无			
  * 返回值：星期几，十进制，1~7
  * 说  明：无
*******************************************************************************/
u8 DS1307_GetDay(void)
{
	u8 temp = 0;
	temp = DS1307_ReadReg(REG_DAY);
	return BCDToDec(temp & 0x07);
}
/*******************************************************************************
  * 函数名：DS1307_GetMonth
  * 功  能：获取月份
  * 参  数：无			
  * 返回值：月份，十进制，1~12
  * 说  明：无
*******************************************************************************/
u8 DS1307_GetMonth(void)
{
	u8 temp = 0;
	temp = DS1307_ReadReg(REG_MONTH);
	return BCDToDec(temp & 0x1F);
}
/*******************************************************************************
  * 函数名：DS1307_GetDate
  * 功  能：获取日期
  * 参  数：无			
  * 返回值：日，十进制，1~31
  * 说  明：无
*******************************************************************************/
u8 DS1307_GetDate(void)
{
	u8 temp = 0;
	temp = DS1307_ReadReg(REG_DATE);
	return BCDToDec(temp & 0x3F);
}
/*******************************************************************************
  * 函数名：DS1307_GetHour
  * 功  能：获取小时
  * 参  数：无			
  * 返回值：小时，十进制，1~12或0~23
  * 说  明：返回的值需要结合小时模式及AM/PM位区分具体时间
*******************************************************************************/
u8 DS1307_GetHour(void)
{
	u8 temp = 0;
	temp = DS1307_ReadReg(REG_HOUR);
	if ((temp & 0x40) == 0x40)//12小时模式
    {
        return BCDToDec(temp & 0x1F);
    }else//24小时模式
    {
        return BCDToDec(temp & 0x3F);
    }
}
/*******************************************************************************
  * 函数名：DS1307_GetHourMode
  * 功  能：获取小时模式
  * 参  数：无			
  * 返回值：0,24小时模式，1,12小时模式
  * 说  明：bit6
*******************************************************************************/
u8 DS1307_GetHourMode(void)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_HOUR);
    temp &= 0x40;
    return (temp >> 6);
}
/*******************************************************************************
  * 函数名：DS1307_SetHourMode
  * 功  能：设置小时模式
  * 参  数：mode，0,24小时模式，1,12小时模式			
  * 返回值：无
  * 说  明：bit6，datasheet要求，更改模式时，小时必须重新初始化，
            因此先读取原小时时间，再设置模式，再将小时写入寄存器
*******************************************************************************/
void DS1307_SetHourMode(u8 mode)
{
    u8 hour = 0;//原时间
    u8 temp = 0;//原模式
    u8 reg = 0;//写入寄存器的值
    temp = DS1307_GetHourMode();
    if (mode != temp)//修改模式
    {
        reg |= ((mode & 0x01) << 6);//模式在bit6
        hour = DS1307_ReadReg(REG_HOUR);;//读取原寄存器的值，保存原时间        
        if (mode == 0)//改为24小时模式，之前是12小时模式，先判断AM/PM
        {
            if ((hour & 0x20) == 0x20)//bit5,1=PM
            {
                hour &= 0x1F;//提取0~4位的时间
                hour = BCDToDec(hour);//BCD转为十进制
                hour += 12;
                reg |= DecToBCD(hour);//BCD
            }else//AM
            {
                hour &= 0x1F;//提取0~4位的时间
                reg |= hour;
            }
        }else//改为12小时模式，之前是24小时模式
        {
            hour &= 0x3F;
            hour = BCDToDec(hour);//BCD转为十进制
            if (hour > 12)//PM
            {
                hour -= 12;
                reg |= DecToBCD(hour);//BCD
                reg |= 0x20;//bit5置1
            }else//AM
            {
                reg |= DecToBCD(hour);//BCD
                reg &= 0xDF;//bit5置0
            }
        }
    }
    DS1307_WriteReg(REG_HOUR, reg);	
}
/*******************************************************************************
  * 函数名：DS1307_SetAMPM
  * 功  能：设置AM/PM模式
  * 参  数：data，0为AM上午，1为PM下午		
  * 返回值：无
  * 说  明：小时寄存器bit5，须在12小时模式下使用
*******************************************************************************/
void DS1307_SetAMPM(u8 dat)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_HOUR);//先把原数据读出
    (dat == 0) ? (temp &= 0xDF) : (temp |= 0x20);
    DS1307_WriteReg(REG_HOUR, temp);
}
/*******************************************************************************
  * 函数名：DS1307_GetAMPM
  * 功  能：读取AM/PM模式
  * 参  数：无		
  * 返回值：0为AM上午，1为PM下午
  * 说  明：小时寄存器bit5，须在12小时模式下使用
*******************************************************************************/
u8 DS1307_GetAMPM(void)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_HOUR);
    return ((temp & 0x20) >> 5);
}
/*******************************************************************************
  * 函数名：DS1307_GetMinute
  * 功  能：获取分钟
  * 参  数：无			
  * 返回值：分钟，十进制，0~59
  * 说  明：无
*******************************************************************************/
u8 DS1307_GetMinute(void)
{
	u8 temp = 0;
	temp = DS1307_ReadReg(REG_MIN);
	return BCDToDec(temp & 0x7F);
}
/*******************************************************************************
  * 函数名：DS1307_GetSecond
  * 功  能：获取秒
  * 参  数：无			
  * 返回值：秒，十进制，0~59
  * 说  明：无
*******************************************************************************/
u8 DS1307_GetSecond(void)
{
	u8 temp = 0;
	temp = DS1307_ReadReg(REG_SEC);
	return BCDToDec(temp & 0x7F);
}
/*******************************************************************************
  * 函数名：DS1307_SetYear
  * 功  能：写入年份
  * 参  数：year：年份，十进制，2000~2099			
  * 返回值：无
  * 说  明：将十进制转为BCD码
*******************************************************************************/
void DS1307_SetYear(u16 year)
{
	u8 temp = DecToBCD(year);
	DS1307_WriteReg(REG_YEAR, temp);	
}
/*******************************************************************************
  * 函数名：DS1307_SetDay
  * 功  能：写入星期几
  * 参  数：day：星期几，1~7			
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void DS1307_SetDay(u8 day)
{
	DS1307_WriteReg(REG_DAY, day & 0x07);	
}
/*******************************************************************************
  * 函数名：DS1307_SetMonth
  * 功  能：写入月份
  * 参  数：month：月份，1~12			
  * 返回值：无
  * 说  明：转为BCD码
*******************************************************************************/
void DS1307_SetMonth(u8 month)
{
    u8 temp = DecToBCD(month);
	DS1307_WriteReg(REG_MONTH, temp & 0x1F);
}
/*******************************************************************************
  * 函数名：DS1307_SetDate
  * 功  能：写入日
  * 参  数：date：日，1~31			
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void DS1307_SetDate(u8 date)
{
    u8 temp = DecToBCD(date);
	DS1307_WriteReg(REG_DATE, temp & 0x3F);
}
/*******************************************************************************
  * 函数名：DS1307_SetHour
  * 功  能：写入小时
  * 参  数：hour：小时，1~12或0~23		
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void DS1307_SetHour(u8 hour)
{
    u8 temp = DecToBCD(hour);
	DS1307_WriteReg(REG_HOUR, temp & 0x3F);
}
/*******************************************************************************
  * 函数名：DS1307_SetMinute
  * 功  能：写入分钟
  * 参  数：min：分钟，0~59		
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void DS1307_SetMinute(u8 min)
{
    u8 temp = DecToBCD(min);
	DS1307_WriteReg(REG_MIN, temp & 0x7F);
}
/*******************************************************************************
  * 函数名：DS1307_SetSecond
  * 功  能：写入秒
  * 参  数：sec：秒，0~59		
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void DS1307_SetSecond(u8 sec)
{
    u8 temp = DecToBCD(sec);
	DS1307_WriteReg(REG_SEC, temp & 0x7F);
}
/*******************************************************************************
  * 函数名：DS1307_ReadHaltFlag
  * 功  能：读Halt标志
  * 参  数：无			
  * 返回值：无
  * 说  明：无
*******************************************************************************/
u8 DS1307_ReadHaltFlag(void)
{
	u8 temp = 0;
	temp = ((DS1307_ReadReg(REG_SEC) & 0x80) == 0x80) ? 1 : 0;
	return temp;
}
/*******************************************************************************
  * 函数名：DS1307_SetHaltFlag
  * 功  能：Halt标志置1
  * 参  数：无			
  * 返回值：无
  * 说  明：先读80寄存器，再写入CH位
*******************************************************************************/
void DS1307_SetHaltFlag(void)
{
	u8 temp = 0;
	temp = DS1307_GetSecond();
	temp |= 0x80;
	DS1307_WriteReg(REG_SEC, temp);
}
/*******************************************************************************
  * 函数名：DS1307_ClearHaltFlag
  * 功  能：Halt标志置0
  * 参  数：无			
  * 返回值：无
  * 说  明：先读80寄存器，再写入CH位，该位为0，时钟才开始工作
*******************************************************************************/
void DS1307_ClearHaltFlag(void)
{
	u8 temp = 0;
	temp = DS1307_GetSecond();
	temp &= 0x7F;
	DS1307_WriteReg(REG_SEC, temp);
}
/*******************************************************************************
  * 函数名：DS1307_SQWEnable
  * 功  能：使能方波输出
  * 参  数：无			
  * 返回值：无
  * 说  明：bit4写1
*******************************************************************************/
void DS1307_SQWEnable(void)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_CTRL);
    temp |= 0x10;
    DS1307_WriteReg(REG_CTRL, temp);
}
/*******************************************************************************
  * 函数名：DS1307_SQWDisable
  * 功  能：禁止方波输出
  * 参  数：无			
  * 返回值：无
  * 说  明：bit4写0
*******************************************************************************/
void DS1307_SQWDisable(void)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_CTRL);
    temp &= 0xEF;
    DS1307_WriteReg(REG_CTRL, temp);
}
/*******************************************************************************
  * 函数名：DS1307_SetSqureWaveFreq
  * 功  能：设置方波频率
  * 参  数：rate:0,1Hz;1,4.096kHz；2,8.192kHz;3,32.768kHz			
  * 返回值：无
  * 说  明：已经使能方波输出的情况下使用,设置RS0/RS1即bit0/bit1位
*******************************************************************************/
void DS1307_SetSqureWaveFreq(u8 rate)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_CTRL);
    rate &= 0x03; 
    switch (rate)
    {
        case 0: temp &= 0xFC; break;//1Hz
        case 1: temp &= 0xFD; temp |=0x01; break;//4.096kHz
        case 2: temp |= 0x02; temp &=0xFE; break;//8.192kHz
        case 3: temp |= 0x03; break;//32.768kHz
        default: break;
    }
    DS1307_WriteReg(REG_CTRL, temp);
}
/*******************************************************************************
  * 函数名：DS1307_OutHigh
  * 功  能：Out引脚输出高电平
  * 参  数：无			
  * 返回值：无
  * 说  明：bit7写1，在禁止方波输出的情况下使用
*******************************************************************************/
void DS1307_OutHigh(void)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_CTRL);
    temp |= 0x80;
    DS1307_WriteReg(REG_CTRL, temp);
}
/*******************************************************************************
  * 函数名：DS1307_OutLow
  * 功  能：Out引脚输出低电平
  * 参  数：无			
  * 返回值：无
  * 说  明：bit7写0，在禁止方波输出的情况下使用
*******************************************************************************/
void DS1307_OutLow(void)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(REG_CTRL);
    temp &= 0x7F;
    DS1307_WriteReg(REG_CTRL, temp);
}

//BCD转BIN函数
u8 DecToBCD(u8 dec)
{
	u8 temp = ((dec / 10) << 4) | (dec % 10);
	return temp;
}

u8 BCDToDec(u8 bcd)
{
	return (0xff & (bcd>>4))*10 +(0xf & bcd);
}

void DS1307_Init(void)
{
    u8 temp = 0;
    temp = DS1307_ReadReg(0x08);//读RAM第一字节
    if (temp != 0x5A)//不正确，重新初始化
    {        
        DS1307_SetYear(25);//25年
        DS1307_SetDay(6);//星期ri
        DS1307_SetMonth(1);//1月
        DS1307_SetDate(25);//25日
        DS1307_SetHour(20);
        DS1307_SetMinute(41);
        DS1307_SetSecond(0);
        DS1307_SetHourMode(0);//0,24小时模式,1,12小时模式
		// DS1307_ClearHaltFlag();//清除Halt标志
        DS1307_WriteReg(0x08, 0x5A);//写入0x5A
    }
}

void DS1307_Read_Time(void)
{
	gDS1302_TIME[2] = DS1307_GetHour();
	gDS1302_TIME[1] = DS1307_GetMinute();
	gDS1302_TIME[0] = DS1307_GetSecond();
}
